﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LED_Editor.Model;
using System.Collections.ObjectModel;
using System.IO.Ports;

namespace LED_Editor.ControllerProgramming
{
    public class SerialPortProgrammingStrategy : BasicControllerProgrammingStrategy
    {
        private const string ComPortIsNull = "ComPort не проинициализирован (null)";
        public SerialPortProgrammingStrategy(SerialPort comPort)
            : base()
        {
            if (comPort == null)
                throw new ArgumentNullException(ComPortIsNull);
            ComPort = comPort;
        }

        private SerialPort ComPort { get; set; }

        public override void OpenConnection()
        {
            if (ComPort == null)
                throw new InvalidOperationException(ComPortIsNull);

            if (!ComPort.IsOpen)
            {
                ComPort.Open();
                base.OpenConnection(); 
            }
        }

       
        public override void CloseConnection()
        {
            if (ComPort == null)
                throw new InvalidOperationException(ComPortIsNull);

            if (ComPort.IsOpen)
            {
                ComPort.Close();
                base.CloseConnection(); 
            }
        }

        public  void SendQuery(byte query)
        {
            ComPort.Write(new byte[] {Address,query  }, 0, 2);
            base.SendQuery(query);
        }

        public override bool IsOpen
        {
            get
            {
                return ComPort.IsOpen;
            }
        }

        public override int Timeout
        {
            get
            {
                return Math.Max(ComPort.ReadTimeout, ComPort.WriteTimeout );
            }
            set
            {
                ComPort.ReadTimeout = value;
                ComPort.WriteTimeout = value;
            }
        }

        public override void SendFrame(FrameStruct frame)
        {
            byte[] bytes = frame.ToByteArray();
            foreach (var eachFrameByte in bytes)
            {
                ComPort.Write(new byte[] { Address, eachFrameByte }, 0, 2);
            }
            base.SendFrame(frame); 
        }

        public override object WaitAnswer()
        {
            try
            {
                Log("Ожидание ответа...");

                int address = 0; 
                int result  = 0;

                while (true){
                    address = ComPort.ReadByte();
                    result  = ComPort.ReadByte();
                    if (address == Address)
                        break;
                }
                
                Log("Ответ: " + ControllerHelper.GetQueryDescription((byte)result));
                return (byte)result;
            }
            catch (InvalidOperationException e)
            {
                throw new ControllerException("Ошибка чтения последовательного порта", e);
            }
            catch (TimeoutException e)
            {
                throw new ControllerException("Превышено время ожидания при чтении последовательного порта", e);
            }
        }

    }
}
